package com.common.base.widget

import android.animation.Animator
import android.content.Context
import android.util.AttributeSet
import android.view.*
import android.widget.FrameLayout
import android.graphics.PointF
import android.animation.ValueAnimator
import android.animation.AnimatorListenerAdapter
import android.view.animation.AccelerateInterpolator
import android.view.animation.OvershootInterpolator
import kotlin.math.abs


class SlideFrameLayout : FrameLayout {

    private var scaleTouchSlop: Int = 0//为了处理单击事件的冲突
    private var maxVelocity: Float = 0F//计算滑动速度用
    private var limit = 0
    private var pointerId: Int = 0
    private var isTouching = false
    private val firstP = PointF()
    private val lastP = PointF()
    //是否点击过，只允许点击一次
    private var isClick = false

    private var velocityTracker: VelocityTracker? = null//滑动速度变量

    private var listener: SlideFrameLayoutListener? = null

    constructor(context: Context) : super(context) {
        init()
    }

    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
        init()
    }

    constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr) {
        init()
    }

    private fun init() {
        scaleTouchSlop = ViewConfiguration.get(context).scaledTouchSlop
        maxVelocity = ViewConfiguration.get(context).scaledMaximumFlingVelocity.toFloat()
    }

    override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
        if (null == event) {
            return super.onTouchEvent(event)
        }
        acquireVelocityTracker(event)
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                if (isTouching)
                    return true
                isTouching = true
                lastP.set(event.rawX, event.rawY)
                firstP.set(event.rawX, event.rawY)
                pointerId = event.getPointerId(0)
                return true
            }
            MotionEvent.ACTION_MOVE -> {
                val gap = lastP.x - event.rawX
                scrollBy(gap.toInt(), 0)

                lastP.set(event.rawX, event.rawY)
            }
            MotionEvent.ACTION_UP,
            MotionEvent.ACTION_CANCEL -> {
                velocityTracker?.computeCurrentVelocity(1000, maxVelocity)
                val velocityX = (velocityTracker?.getXVelocity(pointerId)) ?: 0F
                if (abs(velocityX) > 1000) {
                    smoothClose(scrollX > 0)
                } else {
                    when {
                        abs(scrollX) > getLimit() -> //否则就判断滑动距离
                            smoothClose(scrollX > 0)
                        abs(scrollX) < 10 -> {
                            if (!isClick) {
                                isClick = true
                                listener?.onClick(view)
                            }
                        }
                        else -> smoothOpen()
                    }
                }
                releaseVelocityTracker()
                isTouching = false
            }
        }

        return super.dispatchTouchEvent(event)
    }

    override fun onInterceptTouchEvent(event: MotionEvent?): Boolean {
        if (null == event) {
            return super.onInterceptTouchEvent(event)
        }

        when (event.action) {
            MotionEvent.ACTION_MOVE -> {
                if (abs(event.rawX - firstP.x) > scaleTouchSlop) {
                    return true
                }
            }
            MotionEvent.ACTION_UP,
            MotionEvent.ACTION_CANCEL -> {
            }
        }
        return super.onInterceptTouchEvent(event)
    }

    private fun acquireVelocityTracker(event: MotionEvent) {
        if (null == velocityTracker) {
            velocityTracker = VelocityTracker.obtain()
        }
        velocityTracker?.addMovement(event)
    }

    private fun releaseVelocityTracker() {
        velocityTracker?.let {
            it.clear()
            it.recycle()
        }
        velocityTracker = null
    }

    private fun getLimit(): Int {
        if (0 == limit) {
            limit = width / 3
        }
        return limit
    }

    private var oepnAnim: ValueAnimator? = null
    private var closeAnim: ValueAnimator? = null
    private fun smoothOpen() {
        cancelAnim()
        oepnAnim = ValueAnimator.ofInt(scrollX, 0)
        oepnAnim?.let {
            it.addUpdateListener { animation ->
                scrollTo(animation.animatedValue as Int, 0)
            }
            it.interpolator = AccelerateInterpolator()
            it.addListener(object : AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator) {
                    listener?.onSlideFrameLayoutOpen(view)
                }
            })
            it.setDuration(300).start()
        }
    }

    private fun smoothClose(isCloseToLeft: Boolean) {
        cancelAnim()
        closeAnim = ValueAnimator.ofInt(scrollX, if (isCloseToLeft) width else -width)
        closeAnim?.let {
            it.addUpdateListener { animation ->
                scrollTo(animation.animatedValue as Int, 0)
            }
            it.interpolator = OvershootInterpolator()
            it.addListener(object : AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator) {
                    listener?.onSlideFrameLayoutClose(view)
                }
            })
            it.setDuration(300).start()
        }
    }

    private fun cancelAnim() {
        oepnAnim?.let {
            if (it.isRunning)
                it.cancel()
        }
        closeAnim?.let {
            if (it.isRunning)
                it.cancel()
        }
    }

    fun isTouching(): Boolean = isTouching

    private var view: View? = null
    fun setView(view: View?) {
        this.view = view
    }

    fun setSlideFrameLayoutListener(listener: SlideFrameLayoutListener?) {
        this.listener = listener
    }

    interface SlideFrameLayoutListener {
        fun onSlideFrameLayoutClose(view: View?)
        fun onSlideFrameLayoutOpen(view: View?)
        fun onClick(view: View?)
    }
}